/**
 * 
 */
package coreAlgorithm;

import java.util.Comparator;

import network.Address;

/**
 * 
 * 
 * @author peter
 * 
 */
public class NodeTriple implements Cloneable {
	private Address address;
	private ID nodeID;
	private long lastSeen;

	public long getLastSeen() {
		return lastSeen;
	}

	public void setLastSeen(long lastSeen) {
		this.lastSeen = lastSeen;
	}

	// public Comparable<?> getIpAddress() {
	// return address.ipAddress;
	// }
	//
	// public int getUdpPort() {
	// return address.udpPort;
	// }

	public Address getAddress() {
		return address;
	}

	public ID getNodeID() {
		return nodeID;
	}

	public boolean equals(Object cmp) {
		if (cmp instanceof NodeTriple) {
			return equals((NodeTriple) cmp);
		} else {
			return false;
		}
	}

	public boolean equals(NodeTriple cmp) {
		return nodeID.equals(cmp.getNodeID());
	}
	
	@Override
	public int hashCode() {
		return nodeID.integerValue();
	}

	public NodeTriple(Address address, ID nodeID, long lastSeen) {
		super();
		if (address == null)
			throw new NullPointerException("Address was null");
		if (nodeID == null)
			throw new NullPointerException("NodeID was null");
		this.address = address;
		this.nodeID = nodeID;
		this.lastSeen = lastSeen;
	}

	public NodeTriple clone() {
		return new NodeTriple(this.getAddress(), this.getNodeID(), this.getLastSeen());
	}

	public String toString() {
		return "NodeTriple: " + nodeID + "(" + nodeID.integerValue() + ")\tLast seen: " + getLastSeen();
	}

	public static final Comparator<NodeTriple> LEAST_RECENTLY_SEEN_FIRST_COMPARATOR = new Comparator<NodeTriple>() {

		@Override
		public int compare(NodeTriple o1, NodeTriple o2) {
			if (o1 == null && o2 == null)
				return 0;
			if (o1 == null)
				return +1;
			if (o2 == null)
				return -1;
			return ((Long) o1.getLastSeen()).compareTo((Long) o2.getLastSeen());
		}
	};
	public static final Comparator<NodeTriple> MOST_RECENTLY_SEEN_FIRST_COMPARATOR = new Comparator<NodeTriple>() {

		@Override
		public int compare(NodeTriple o1, NodeTriple o2) {
			if (o1 == null && o2 == null)
				return 0;
			if (o1 == null)
				return +1;
			if (o2 == null)
				return -1;
			return ((Long) o1.getLastSeen()).compareTo((Long) o2.getLastSeen()) * -1;
		}
	};

	public static final Comparator<NodeTriple> NEAREST_TO_GIVEN_ID_COMPARATOR(final ID demandedID) {
		return new Comparator<NodeTriple>() {
			@Override
			public int compare(NodeTriple o1, NodeTriple o2) {
				if (o1 == null && o2 == null)
					return 0;
				if (o1 == null)
					return +1;
				if (o2 == null)
					return -1;
				ID distanceO1 = o1.getNodeID().applyXOR(demandedID); // That's the valid computation for the XOR-metric
				ID distanceO2 = o2.getNodeID().applyXOR(demandedID);
				// System.out.print("Compare " + distanceO1.integerValue() + " to " + distanceO2.integerValue() + " with given "+ demandedID.integerValue() + ": ");
				if (distanceO1.equals(distanceO2)) {
					// System.out.println("0");
					return 0;
				}
				if (distanceO1.integerValue() < distanceO2.integerValue()) {
					// System.out.println("-1");
					return -1;
				} else {
					// System.out.println(" +1");
					return +1;
				}
			}
		};
	}
}
